home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Turnbull China Bikeride
/
Turnbull China Bikeride - Disc 1.iso
/
DEMON
/
RISCOS2
/
TCP_131S.ARC
/
c
/
ax25cmd
< prev
next >
Wrap
Text File
|
1994-03-05
|
16KB
|
691 lines
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "global.h"
#include "mbuf.h"
#include "ax25.h"
#include "ax_mbx.h"
#include "timer.h"
#include "iface.h"
#include "lapb.h"
#include "cmdparse.h"
#include "session.h"
#include "netuser.h"
#include "misc.h"
static int doaxreset(int, char **);
static int doaxstat(int, char **);
static void dumpstat(struct ax25_cb *);
static int domycall(int, char **);
static int dodigipeat(int, char **);
static int dot1(int, char **);
static int dot2(int, char **);
static int dot3(int, char **);
static int dot4(int, char **);
static int don2(int, char **);
static int domaxframe(int, char **);
static int doheard(int, char **);
static int dopaclen(int, char **);
static int dopthresh(int, char **);
static int doaxwindow(int, char **);
static int mh_compare(const void *, const void *);
char *ax25states[] = {
"Disconnected",
"Conn pending",
"Disc pending",
"Connected",
"Recovery",
"Frame Reject",
};
static struct cmds axcmds[] = {
"digipeat", dodigipeat, 0, NULLCHAR, NULLCHAR,
"heard", doheard, 0, NULLCHAR, NULLCHAR,
"maxframe", domaxframe, 0, NULLCHAR, NULLCHAR,
"mycall", domycall, 0, NULLCHAR, NULLCHAR,
"paclen", dopaclen, 0, NULLCHAR, NULLCHAR,
"pthresh", dopthresh, 0, NULLCHAR, NULLCHAR,
"reset", doaxreset, 2, "ax25 reset <axcb>", NULLCHAR,
"retry", don2, 0, NULLCHAR, NULLCHAR,
"status", doaxstat, 0, NULLCHAR, NULLCHAR,
"t1", dot1, 0, NULLCHAR, NULLCHAR,
"t2", dot2, 0, NULLCHAR, NULLCHAR,
"t3", dot3, 0, NULLCHAR, NULLCHAR,
"t4", dot4, 0, NULLCHAR, NULLCHAR,
"window", doaxwindow, 0, NULLCHAR, NULLCHAR,
NULLCHAR, NULLFP, 0, "ax25 subcommands: digipeat heard maxframe mycall pthresh paclen reset retry\n status t1 t2 t3 t4 window", NULLCHAR,
};
/* Multiplexer for top-level ax25 command */
int doax25(int argc, char **argv)
{
return subcmd(axcmds,argc,argv);
}
static int doaxreset(int argc, char **argv)
{
struct ax25_cb *axp;
extern char notval[];
argc = argc;
axp = (struct ax25_cb *)htol(argv[1]);
if(!ax25val(axp))
{
cwprintf(NULL, notval);
return 1;
}
reset_ax25(axp);
return 0;
}
/* Display AX.25 link level control blocks */
static int doaxstat(int argc, char **argv)
{
register int i;
register struct ax25_cb *axp;
char tmp[10];
extern char notval[];
if(argc < 2)
{
cwprintf(NULL, " &AXB IF Snd-Q Rcv-Q Remote State\r\n");
for(i=0;i<NHASH;i++)
{
for(axp = ax25_cb[i];axp != NULLAX25; axp = axp->next)
{
pax25(tmp,&axp->addr.dest);
cwprintf(NULL, "%8lx %-5s%-8d%-8d%-10s%s\r\n",
(long)axp,axp->interface->name,
len_q(axp->txq),len_mbuf(axp->rxq),
tmp,ax25states[axp->state]);
}
}
return 0;
}
axp = (struct ax25_cb *)htol(argv[1]);
if(!ax25val(axp))
{
cwprintf(NULL, notval);
return 1;
}
dumpstat(axp);
return 0;
}
/* Dump one control block */
static void dumpstat(register struct ax25_cb *axp)
{
char tmp[10];
int i;
if(axp == NULLAX25 || axp->interface == NULLIF)
return;
cwprintf(NULL, "&AXB IF Remote RB V(S) V(R) Unack P Retry State\r\n");
pax25(tmp,&axp->addr.dest);
cwprintf(NULL, "%4x %-5s%-9s",(int)axp,axp->interface->name,tmp);
cwputchar(NULL, axp->rejsent ? 'R' : ' ');
cwputchar(NULL, axp->remotebusy ? 'B' : ' ');
cwprintf(NULL, " %4d %4d",axp->vs,axp->vr);
cwprintf(NULL, " %02u/%02u %u",axp->unack,axp->maxframe,axp->proto);
cwprintf(NULL, " %02u/%02u",axp->retries,axp->n2);
cwprintf(NULL, " %s\r\n",ax25states[axp->state]);
cwprintf(NULL, "T1: ");
if(run_timer(&axp->t1))
cwprintf(NULL, "%lu",(axp->t1.start - axp->t1.count) * MSPTICK);
else
cwprintf(NULL, "stop");
cwprintf(NULL, "/%lu ms; ",axp->t1.start * MSPTICK);
cwprintf(NULL, "T2: ");
if(run_timer(&axp->t2))
cwprintf(NULL, "%lu",(axp->t2.start - axp->t2.count) * MSPTICK);
else
cwprintf(NULL, "stop");
cwprintf(NULL, "/%lu ms; ",axp->t2.start * MSPTICK);
cwprintf(NULL, "T3: ");
if(run_timer(&axp->t3))
cwprintf(NULL, "%lu",(axp->t3.start - axp->t3.count) * MSPTICK);
else
cwprintf(NULL, "stop");
cwprintf(NULL, "/%lu ms; ",axp->t3.start * MSPTICK);
cwprintf(NULL, "T4: ");
if(run_timer(&axp->t4))
cwprintf(NULL, "%lu",(axp->t4.start - axp->t4.count) * MSPTICK);
else
cwprintf(NULL, "stop");
cwprintf(NULL, "/%lu ms\r\n",axp->t4.start * MSPTICK);
if(axp->addr.ndigis == 0)
return;
cwprintf(NULL, "Digipeaters:");
for(i=0;i<axp->addr.ndigis;i++)
{
pax25(tmp,&axp->addr.digis[i]);
cwprintf(NULL, " %s",tmp);
}
cwprintf(NULL, "\r\n");
}
/* Display or change our AX.25 address */
static int domycall(int argc, char **argv)
{
char buf[15];
if(argc < 2)
{
pax25(buf,&mycall);
cwprintf(NULL, "%s\r\n",buf);
return 0;
}
if(setcall(&mycall,argv[1]) == -1)
return -1;
mycall.ssid |= E;
return 0;
}
/* Control AX.25 digipeating */
static int dodigipeat(int argc, char **argv)
{
extern int digipeat;
extern int32 digisent;
if(argc == 1)
{
cwprintf(NULL, "digipeat %s\r\n",digipeat ? "on" : "off");
cwprintf(NULL, "digipeated packets = %lu\r\n",digisent);
}
else
{
if(strcmp(argv[1],"on") == 0)
digipeat = 1;
else
digipeat = 0;
}
return(0);
}
/* Set retransmission timer */
static int dot1(int argc, char **argv)
{
extern int16 t1init;
if(argc == 1)
{
cwprintf(NULL, "T1 %lu ms\r\n",(long)t1init * MSPTICK);
}
else
{
t1init = (int16)(atol(argv[1]) / MSPTICK);
}
return(0);
}
/* Set acknowledgement delay timer */
static int dot2(int argc, char **argv)
{
extern int16 t2init;
if(argc == 1)
{
cwprintf(NULL, "T2 %lu ms\r\n",(long)t2init * MSPTICK);
}
else
{
t2init = (int16)(atol(argv[1]) / MSPTICK);
}
return(0);
}
/* Set idle timer */
static int dot3(int argc, char **argv)
{
extern int16 t3init;
if(argc == 1)
{
cwprintf(NULL, "T3 %lu ms\r\n",(long)t3init * MSPTICK);
}
else
{
t3init = (int16)(atol(argv[1]) / MSPTICK);
}
return(0);
}
/* Set link redundancy timer */
static int dot4(int argc, char **argv)
{
extern int16 t4init;
if(argc == 1)
{
cwprintf(NULL, "T4 %lu sec\r\n",((long)t4init * MSPTICK) / 1000);
}
else
{
t4init = (int16)((atol(argv[1]) * 1000) / MSPTICK);
}
return(0);
}
/* Set retry limit count */
static int don2(int argc, char **argv)
{
extern int16 n2;
if(argc == 1)
{
cwprintf(NULL, "Retry %u\r\n",n2);
}
else
{
n2 = (int16)(atoi(argv[1]));
}
return(0);
}
/* Set maximum number of frames that will be allowed in flight */
static int domaxframe(int argc, char **argv)
{
extern int16 maxframe;
if(argc == 1)
{
cwprintf(NULL, "Maxframe %u\r\n",maxframe);
}
else
{
maxframe = (int16)(atoi(argv[1]));
}
return(0);
}
/* Display the last x number of stations heard in the ether */
static int doheard(int argc, char **argv)
{
extern struct ax25mh mhlist[]; /* the mheard table (ax25.c) */
char mhcallsign[10]; /* field for call sign dumpout */
char *mhtime; /* ascii time representation */
int mhcolumn = 0; /* page column display counter */
int mh_entry; /* index into mhlist */
argv = argv;
if(argc > 1) /* any second arg flushes mhlist */
{
for(mh_entry = 0; mh_entry < 40; mh_entry++)
mhlist[mh_entry].mheard_time = 0; /* 0 time = empty */
return(0);
}
qsort((void *)mhlist, 40, sizeof(struct ax25mh), mh_compare);
for(mh_entry = 0; mh_entry < 40; mh_entry++)
{
if(mhlist[mh_entry].mheard_time == 0) /* empty entry? */
break; /* all done now */
if(mh_entry == 0)
cwprintf(NULL, "AX25 Stations heard. (* = heard directly)\r\n");
pax25(mhcallsign,&mhlist[mh_entry].mheard_call); /* dump callsign */
mhtime = ctime(&mhlist[mh_entry].mheard_time); /* get time in ascii */
rip(mhtime); /* lose the \n etc */
cwprintf(NULL, "%s %s %-11s", mhtime, mhlist[mh_entry].mheard_digi ? " " : "*", mhcallsign) ;
mhcolumn++;
if(mhcolumn == 2)
{
mhcolumn = 0;
cwprintf(NULL, "\r\n");
}
}
if(mhcolumn == 1)
cwprintf(NULL, "\r\n");
return(0);
}
static int mh_compare(const void *mh1, const void *mh2)
{
struct ax25mh *mheard1 = (struct ax25mh *)mh1;
struct ax25mh *mheard2 = (struct ax25mh *)mh2;
if(mheard1->mheard_time == mheard2->mheard_time)
return(0);
if(mheard1->mheard_time > mheard2->mheard_time)
return(-1);
else
return(1);
}
/* Set maximum length of I-frame data field */
static int dopaclen(int argc, char **argv)
{
extern int16 paclen;
if(argc == 1)
{
cwprintf(NULL, "Paclen %u\r\n",paclen);
}
else
{
paclen = atoi(argv[1]);
}
return(0);
}
/* Set size of I-frame above which polls will be sent after a timeout */
static int dopthresh(int argc, char **argv)
{
extern int16 pthresh;
if(argc == 1)
{
cwprintf(NULL, "Pthresh %u\r\n",pthresh);
}
else
{
pthresh = atoi(argv[1]);
}
return(0);
}
/* Set high water mark on receive queue that triggers RNR */
static int doaxwindow(int argc, char **argv)
{
extern int16 axwindow;
if(argc == 1)
{
cwprintf(NULL, "Axwindow %u\r\n",axwindow);
}
else
{
axwindow = atoi(argv[1]);
}
return(0);
}
/* End of ax25 subcommands */
/* Initiate interactive AX.25 connect to remote station */
int doconnect(int argc, char **argv)
{
struct ax25_addr dest;
struct ax25 addr;
struct interface *ifp;
struct session *s;
extern int16 axwindow;
int i;
for(ifp = ifaces; ifp != NULLIF; ifp = ifp->next)
if(strcmp(argv[1],ifp->name) == 0)
break;
if(ifp == NULLIF)
{
cwprintf(NULL, "Interface %s unknown\r\n",argv[1]);
return 1;
}
if(strcmp(argv[1],"netrom") == 0)
{
cwprintf(NULL, "Connect on netrom interface not supported.\r\n");
return 1;
}
setcall(&dest,argv[2]);
/* See if a session already exists */
for(s = sessions; s < &sessions[nsessions]; s++)
{
if(s->type == AX25TNC
&& addreq(&s->cb.ax25_cb->addr.dest,&dest))
{
cwprintf(NULL, "Session %u to %s already exists\r\n",
s - sessions,argv[2]);
return 1;
}
}
/* Allocate a session descriptor */
if((s = newsession()) == NULLSESSION)
{
cwprintf(NULL, "Too many sessions\r\n");
return 1;
}
if((s->name = malloc((unsigned)strlen(argv[2])+1)) != NULLCHAR)
strcpy(s->name,argv[2]);
s->type = AX25TNC;
s->parse = (void(*)())ax_parse;
current = s;
/* use callsign dedicated to this interface */
memcpy(&addr.source,ifp->hwaddr,sizeof(struct ax25_addr));
setcall(&addr.dest,argv[2]);
for(i=3; i < argc; i++)
setcall(&addr.digis[i-3],argv[i]);
addr.ndigis = i - 3;
s->cb.ax25_cb = open_ax25(&addr, axwindow, (void(*)())ax_rx, (void(*)())ax_tx, (void(*)())ax_state, ifp, (char *)s);
go(s);
return 0;
}
/* Display changes in AX.25 state */
void ax_state(struct ax25_cb *axp, int old, int new)
{
struct session *s;
s = (struct session *)axp->user;
if (current != NULLSESSION && current->type == AX25TNC && current == s)
{
/* Don't print transitions between CONNECTED and RECOVERY */
if (new != RECOVERY && !(old == RECOVERY && new == CONNECTED))
cwprintf(NULL, "%s\r\n", ax25states[new]);
if (new == DISCONNECTED)
cmdmode();
}
if (new == DISCONNECTED)
{
axp->user = NULLCHAR;
freesession(s);
}
}
/* Handle typed characters on AX.25 connection */
void ax_parse(char *buf, int16 cnt)
{
struct mbuf *bp;
register char *cp;
char c;
if(current == NULLSESSION || current->type != AX25TNC)
return; /* "can't happen" */
/* If recording is on, record outgoing stuff too */
if(current->record != NULLFILE)
fwrite(buf,1,cnt,current->record);
/* Allocate buffer and start it with the PID */
bp = alloc_mbuf(cnt+1);
*bp->data = PID_NO_L3;
bp->cnt++;
/* Copy keyboard buffer to output, stripping line feeds */
cp = bp->data + 1;
while(cnt-- != 0)
{
c = *buf++;
if(c != '\r\n')
{
*cp++ = c;
bp->cnt++;
}
}
send_ax25(current->cb.ax25_cb,bp);
}
/* Handle new incoming terminal sessions
* This is the default receive upcall function, used when
* someone else connects to us
*/
void ax_incom(register struct ax25_cb *axp, int16 cnt)
{
if (ax25mbox)
{
mbx_incom(axp,cnt) ;
}
else
{
ax_session(axp,cnt) ;
}
return ;
}
/* This function sets up an ax25 chat session */
void ax_session(register struct ax25_cb *axp, int16 cnt)
{
struct session *s;
char remote[10];
extern char hostname[];
extern int attended;
char *cp;
time_t t;
cnt = cnt;
time(&t);
cp = ctime(&t);
rip(cp);
pax25(remote,&axp->addr.dest);
if((s = newsession()) == NULLSESSION)
{
/* Out of sessions */
disc_ax25(axp);
return;
}
s->type = AX25TNC;
s->name = malloc((int16)strlen(remote)+1);
s->cb.ax25_cb = axp;
s->parse = (void(*)())ax_parse;
strcpy(s->name,remote);
axp->r_upcall = (void(*)())ax_rx;
axp->s_upcall = ax_state;
axp->t_upcall = (void(*)())ax_tx;
axp->user = (char *)s;
cwprintf(NULL, "%s : Incoming AX25 session %u from %s\r\n",cp,s - sessions,remote);
log_event(NULL,"AX25 Chatter session requested : %s",remote);
if(attended)
aprintf(axp,"Welcome %s to the %s system's 'Chat' mode.\r",remote,hostname);
else
aprintf(axp,"Sorry %s, the %s system is UNATTENDED.\r",remote,hostname);
}
/* Handle incoming terminal traffic */
void ax_rx(struct ax25_cb *axp, int16 cnt)
{
extern int ttyflow;
register struct mbuf *bp;
register char *s;
register char *t;
char *line;
/* Hold output if we're typing */
if(mode != CONV_MODE || current == NULLSESSION || ttyflow == 0
|| current->type != AX25TNC || current->cb.ax25_cb != axp)
return;
if((bp = recv_ax25(axp,cnt)) == NULLBUF)
return;
/* Display received characters, translating CR's to CR/LF */
if ((line = s = malloc(len_mbuf(bp) + 1)) == NULLCHAR)
{
cwprintf(NULL, "Out of memory in AX25CMD\r\n");
free_p(bp);
return;
}
while (bp != NULLBUF)
{
t = bp->data;
while(bp->cnt-- > 0)
{
if (*t == '\r')
*(++t) = '\n';
*s++ = *t++;
}
bp = free_mbuf(bp);
}
if (current->record)
{
fwrite(line, 1, s - line, current->record);
fflush(current->record);
}
*s = '\0';
cwputs(NULL, line);
free(line);
}
/* Handle transmit upcalls. Used only for file uploading */
void ax_tx(struct ax25_cb *axp, int16 cnt)
{
register char *cp;
struct session *s;
register struct mbuf *bp;
int16 size;
int c;
if((s = (struct session *)axp->user) == NULLSESSION
|| s->upload == NULLFILE)
return;
while(cnt != 0)
{
size = min(cnt,axp->paclen+1);
if((bp = alloc_mbuf(size)) == NULLBUF)
break;
cp = bp->data;
/* Start with the PID */
*cp++ = PID_NO_L3;
bp->cnt++;
/* Now send data characters, translating between local
* keyboard end-of-line sequences and the (unwritten)
* AX.25 convention, which is carriage-return only
*/
while(bp->cnt < size)
{
if((c = getc(s->upload)) == EOF)
break;
if(c == '\n')
c = '\r';
*cp++ = c;
bp->cnt++;
}
if(bp->cnt > 1)
{
send_ax25(axp,bp);
}
else
{
/* Empty frame, don't bother sending */
free_p(bp);
break;
}
cnt -= bp->cnt;
}
if(cnt != 0)
{
/* Error or end-of-file */
fclose(s->upload);
s->upload = NULLFILE;
free(s->ufile);
s->ufile = NULLCHAR;
}
}